<?php
/**
Plugin Name: aLinks
Plugin URI: http://alinks.headzoo.com
Description: A WordPress plugin that automatically links keywords in your blog post.
Author: Sean Hickey
Version: 2.0.2
Author URI: http://www.headzoo.com
*/
define('ALINKS_RUNNING', true);
define('ALINKS_MU', false);
define('ALINKS_MU_ADMIN_ONLY', false);

set_include_path(
	dirname(__FILE__)
	. PATH_SEPARATOR
	. dirname(__FILE__) . '/includes'
	. PATH_SEPARATOR
	. get_include_path()
);

/**
 * To hackers,
 *
 * Post Parsing:
 * The class Alinks_Post_Parser_Abstract is the main class. The method
 * parse() is responsible for parsing the posts, and turning the
 * phrases into links. If you want to change something about the way
 * aLinks parses the posts, that's the method to edit.
 *
 * Menu User Levels:
 * If you want to change the user level needed to view the admin menus,
 * then change the value of ACCESS_LEVEL in the class Alinks_Menu. By default
 * it's set to 10.
 */
 
require_once('Alinks/Version.php');
require_once('Alinks/Registry.php');
require_once('Alinks/Error.php');
require_once('Alinks/Cacher/Factory.php');
require_once('Alinks/Keyphrase/Keeper.php');
require_once('Alinks/Factory/Keeper.php');
require_once('Alinks/Settings.php');
require_once('Alinks/Ajax.php');
require_once('Alinks/ImportExport/Export/Ajax.php');

add_action('init', 'alinks_bootstrap');
add_action('wp_ajax_alinks_ajax_dispatch', array('Alinks_Ajax', 'dispatch'));
register_activation_hook(__FILE__, 'alinks_activate');

/**
 * The aLinks "bootstrap" function
 *
 * Called by WordPress's 'init' action
 */
function alinks_bootstrap()
{
	global $wpdb, $table_prefix, $wp_version;
	if (ALINKS_MU == true) {
		global $wpmuBaseTablePrefix;
	}
	
	if (get_option('alinks_error')) {
		add_action('admin_notices', 'alinks_installation_error');
		return;
	}
	
	$temp_path 			= dirname(__FILE__) . '/temp';
	$log_path 			= "$temp_path/logs";
	$cache_path 		= "$temp_path/cache";
	$factories_path 	= dirname(__FILE__) . '/factories';

	Alinks_Error::setLogPath($log_path);
	Alinks_Registry::set('alinks_mu', ALINKS_MU);
	Alinks_Registry::set('alinks_mu_admin_only', ALINKS_MU_ADMIN_ONLY);
	Alinks_Registry::set('plugin_basename', plugin_basename(__FILE__));
	Alinks_Registry::set('temp_path', $temp_path);
	Alinks_Registry::set('log_path', $log_path);
	Alinks_Registry::set('cache_path', $cache_path);
	Alinks_Registry::set('factories_path', $factories_path);
	Alinks_Registry::set('wpdb', $wpdb);
	if (Alinks_Registry::get('alinks_mu_admin_only')) {
		Alinks_Registry::set('table_prefix', $wpmuBaseTablePrefix . '1_');
	} else {
		Alinks_Registry::set('table_prefix', $table_prefix);
	}
	Alinks_Registry::set('Alinks_ImportExport_Export_Ajax', new Alinks_ImportExport_Export_Ajax());
	Alinks_Registry::set('debugging', false);
	
	/**
	 * Check if this request is for keyphrases exported via
	 * the keyphrases menu.
	 */
	Alinks_ImportExport_Export_Ajax::init();
	
	/**
	 * Setup caching. If the user has caching enabled through WordPress,
	 * we'll just use that. Otherwise we'll use our own file caching.
	 */
	try {
		if (defined('ENABLE_CACHE') && ENABLE_CACHE == true) {
			$cacher = Alinks_Cacher_Factory::factory('wordpress', array());
		} else {
			$cacher = Alinks_Cacher_Factory::factory('file', array('dir' => $cache_path));
		}
		Alinks_Registry::set('Alinks_Cacher', $cacher);
	} catch (Alinks_Cacher_Exception $e) {
		Alinks_Error::showException($e, Alinks_Error::logException($e));
		return;
	}

	/**
	 * Setup Alinks_Settings to get aLinks and factory options.
	 */
	try {
		Alinks_Settings::setDb($wpdb, Alinks_Registry::get('table_prefix'));
		Alinks_Settings::setCacher($cacher);
	} catch (Exception $e) {
		Alinks_Error::showException($e, Alinks_Error::logException($e));
		return;
	}
	
	if (Alinks_Registry::get('alinks_mu')) {
		$alinks_path = plugin_basename(dirname(__FILE__));
		if (Alinks_Registry::get('alinks_mu_admin_only')) {
			$alinks_url = Alinks_Settings::get('alinks', 'home') . '/wp-content/mu-plugins';
		} else {
			$alinks_url = Alinks_Settings::get('alinks', 'home') . '/wp-content/plugins';
		}
	} else {
		$alinks_path = ABSPATH . 'wp-content/plugins/' . plugin_basename(dirname(__FILE__));
		$alinks_url = Alinks_Settings::get('alinks', 'home') . '/wp-content/plugins/' . plugin_basename(dirname(__FILE__));
	}
	Alinks_Registry::set('alinks_path',	$alinks_path);
	Alinks_Registry::set('alinks_url', $alinks_url);

	/**
	 * Get all the defined keyphrases. Setup a shutdown hook that will
	 * take care of saving any changed keyphrases to the database.
	 */
	try {
		$keyphrases = new Alinks_Keyphrase_Keeper($wpdb, Alinks_Registry::get('table_prefix'), $cacher);
		Alinks_Registry::set('Alinks_Keyphrase_Keeper', $keyphrases);
		Alinks_Registry::set('keyphrases', null, array($keyphrases, 'fetchAll'));
		add_action('shutdown', array($keyphrases, 'shutdown'));
	} catch (Exception $e) {
		Alinks_Error::showException($e, Alinks_Error::logException($e));
		return;
	}

	try {
		$factories = new Alinks_Factory_Keeper($factories_path, Alinks_Settings::get(), Alinks_Version::VERSION, $wp_version);
		if (!empty($_FILES)) {
			/**
			 * @see Alinks_Zip
			 */
			require_once('Alinks/Zip.php');
			$factories->setZipper(new Alinks_Zip());
		}
		Alinks_Registry::set('Alinks_Factory_Keeper', $factories);
		Alinks_Registry::set('factories', null, array($factories, 'fetchAll'));
	} catch (Exception $e) {
		Alinks_Error::showException($e, Alinks_Error::logException($e));
		return;
	}

	if (is_admin()) {
		if (Alinks_Registry::get('alinks_mu_admin_only')) {
			if (is_site_admin()) {
				/**
				 * @see Alinks_Menu
				 */
				require_once('Alinks/Menu.php');
				$menu = new Alinks_Menu();
				$menu->init();
				add_action('admin_menu', array($menu, 'add'));
			}
		} else {
			/**
			 * @see Alinks_Menu
			 */
			require_once('Alinks/Menu.php');
			$menu = new Alinks_Menu();
			$menu->init();
			add_action('admin_menu', array($menu, 'add'));
		}
		
		if (!Alinks_Registry::get('alinks_mu')) {
			/**
			 * @see Alinks_Post_Scraper
			 */
			require_once('Alinks/Post/Scraper.php');
			add_action('save_post', array(new Alinks_Post_Scraper(), 'scrape'));
		}
	}
	
	if (!Alinks_Ajax::isAjax()) {
		/**
		 * @see Alinks_Post_Parser
		 */
		require_once('Alinks/Post/Parser.php');
		
		/**
		 * Setup the parser. This is the class that actually does the 
		 * work of parsing the posts.
		 */
		$post_parser = new Alinks_Post_Parser();
		$post_parser->setCacher($cacher);
		add_action('the_content', array($post_parser, 'parse'), 1);
		add_action('save_post', array($post_parser, 'postUpdated'));
		add_action('delete_post', array($post_parser, 'postUpdated'));
		
		/**
		 * Only if the user wants the comments to be parsed too. By default
		 * we won't do this.
		 */
		if (Alinks_Settings::get('alinks', Alinks_Settings::PARSE_COMMENTS, Alinks_Settings::DEFAULT_PARSE_COMMENTS)) {
			add_action('comment_text', array($post_parser, 'parse'), 1);
			add_action('edit_comment', array($post_parser, 'commentUpdated'));
			add_action('delete_comment', array($post_parser, 'commentUpdated'));
		}
	}
}

/**
 * Called when aLinks is activated
 */
function alinks_activate()
{
	global $wpdb, $table_prefix;

	/**
	 * @see Alinks_Install
	 */
	require_once('Alinks/Install.php');
	$installer = new Alinks_Install(dirname(__FILE__), $wpdb, $table_prefix);
	$installer->install();
}

/**
 * Handles an installation error
 *
 * The Alinks_Install class will set the option 'alinks_error' if there
 * was an installation error. When aLinks runs, it checks for the presence
 * of this option. If found, this function is called.
 *
 * The function displays an error message to the user, and then deactivates
 * the plugin.
 */
function alinks_installation_error()
{
	?>
	<div id='alinks_notice' class='updated fade-ff0000'>
		<p><strong>aLinks Installation Error</strong><br />
		<?php echo get_option('alinks_error'); ?></p>
	</div>
	<?php
	
	delete_option('alinks_error');
	$current = get_option('active_plugins');
	array_splice($current, array_search(plugin_basename(__FILE__), $current), 1);
	update_option('active_plugins', $current);
	do_action('deactivate_' . trim(plugin_basename(__FILE__)));
}

/**
 * For PHP versions less than 5.2
 *
 * Thank you Steve!
 *
 * @see http://us2.php.net/manual/en/function.json-encode.php#82904
 */
if (!function_exists('json_encode'))
{
  function json_encode($a=false)
  {
    if (is_null($a)) return 'null';
    if ($a === false) return 'false';
    if ($a === true) return 'true';
    if (is_scalar($a))
    {
      if (is_float($a))
      {
        // Always use "." for floats.
        return floatval(str_replace(",", ".", strval($a)));
      }

      if (is_string($a))
      {
        static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
        return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"';
      }
      else
        return $a;
    }
    $isList = true;
    for ($i = 0, reset($a); $i < count($a); $i++, next($a))
    {
      if (key($a) !== $i)
      {
        $isList = false;
        break;
      }
    }
    $result = array();
    if ($isList)
    {
      foreach ($a as $v) $result[] = json_encode($v);
      return '[' . join(',', $result) . ']';
    }
    else
    {
      foreach ($a as $k => $v) $result[] = json_encode($k).':'.json_encode($v);
      return '{' . join(',', $result) . '}';
    }
  }
}